#ifndef _NE_RENDER_SYSTEM_H_
#define _NE_RENDER_SYSTEM_H_

#include <common/Singleton.h>
#include <graphics/RenderPass.h>
#include <graphics/Viewport.h>
#include <graphics/Fog.h>

namespace ne
{
    class NEAPI RenderSystem : public Singleton<RenderSystem>
    {
        public:
            RenderSystem();

            bool initialize();

            bool isReady() const;

            void setRenderOption(const RenderOption &ro);

            bool render(const RenderPass &pass);

            bool render(const PrimitiveDeclaration &pd);

            void flush();

            void finish();

            void reset();

            void checkError() const;

            // Matrix
            void setProjectionMatrix(const Matrix4 &m);
            const Matrix4& getProjectionMatrix() const;

            void setViewMatrix(const Matrix4 &m);
            const Matrix4& getViewMatrix() const;

            void setTextureMatrix(const Matrix4 &m);
            const Matrix4& getTextureMatrix() const;

            void setColorMatrix(const Matrix4 &m);
            const Matrix4& getColorMatrix() const;

            // Clear Buffer Bit
            void clear();
            void clear(const bool clearColor, const bool clearDepth, const bool clearStencil=false, const bool clearAccum=false);

            void setClearColor(const Color &color);
            Color getClearColor() const;
            void setColorWriteMask(const byte mask);
            byte getColorWriteMask() const;

            // Alpha Test
            void setAlphaTestFunc(const CompareFunction f, const real a);
            CompareFunction getAlphaTestFunc() const;
            real getAlphaTestValue() const;
            void setAlphaTestEnable(const bool b);
            bool isAlphaTestEnable() const;

            // Depth Test
            void setClearDepth(const real d);
            real getClearDepth() const;
            void setDepthTestFunc(const CompareFunction f);
            CompareFunction getDepthTestFunc() const;
            void setDepthTestEnable(const bool b);
            bool isDepthTestEnable() const;
            void setDepthWriteEnable(const bool b);
            bool isDepthWriteEnable() const;

            void setDepthRange(const real n, const real f);
            real getDepthNearRange() const;
            real getDepthFarRange() const;

            // Stencil Test
            void setClearStencil(const int a);
            int getClearStencil() const;

            void setStencilTestFunc(const CompareFunction f, const int value, const uint32_t mask);
            int getStencilTestValue() const;
            uint32_t getStencilTestMask() const;
            CompareFunction getStencilTestFunc() const;

            void setStencilFrontTestFunc(const CompareFunction f, const int value, const uint32_t mask);
            int getStencilFrontTestValue() const;
            uint32_t getStencilFrontTestMask() const;
            CompareFunction getFrontStencilTestFunc() const;

            void setStencilBackTestFunc(const CompareFunction f, const int value, const uint32_t mask);
            int getStencilBackTestValue() const;
            uint32_t getStencilBackTestMask() const;
            CompareFunction getStencilBackTestFunc() const;

            void setStencilOperations(const StencilOperation srcFailOpt, const StencilOperation dstFailOpt, const StencilOperation dstPassOpt);
            StencilOperation getStencilSrcFailOperation() const;
            StencilOperation getStencilDstFailOperation() const;
            StencilOperation getStencilDstPassOperation() const;

            void setStencilFrontOperations(const StencilOperation srcFailOpt, const StencilOperation dstFailOpt, const StencilOperation dstPassOpt);
            StencilOperation getStencilFrontSrcFailOperation() const;
            StencilOperation getStencilFrontDstFailOperation() const;
            StencilOperation getStencilFrontDstPassOperation() const;

            void setStencilBackOperations(const StencilOperation srcFailOpt, const StencilOperation dstFailOpt, const StencilOperation dstPassOpt);
            StencilOperation getStencilBackSrcFailOperation() const;
            StencilOperation getStencilBackDstFailOperation() const;
            StencilOperation getStencilBackDstPassOperation() const;

            void setStencilWriteEnableMask(const uint32_t mask);
            uint32_t getStencilWriteEnableMask() const;

            void setStencilFrontWriteEnableMask(const uint32_t mask);
            uint32_t getStencilFrontWriteEnableMask() const;

            void setStencilBackWriteEnableMask(const uint32_t mask);
            uint32_t getStencilBackWriteEnableMask() const;

            void setStencilTestEnable(const bool b);
            bool isStencilTestEnable() const;

            // Scissor Test
            void setScissor(const int left, const int bottom, const uint32_t width, const uint32_t height);
            int getScissorLeft() const;
            int getScissorRight() const;
            int getScissorTop() const;
            int getScissorBottom() const;
            uint32_t getScissorWidth() const;
            uint32_t getScissorHeight() const;
            void setScissorTestEnable(const bool b);
            bool isScissorTestEnable() const;

            // Cull Face
            void setFrontFaceType(const FrontFaceType fft);
            FrontFaceType getFrontFaceType() const;
            void setCullFaceType(const FaceType ft);
            FaceType getCullFaceType() const;
            void setCullFaceEnable(const bool b);
            bool isCullFaceEnable() const;

            // Polygon Mode
            void setPolygonMode(const PolygonMode pm);
            PolygonMode getPolygonMode() const;
            void setPolygonModeFront(const PolygonMode pm);
            PolygonMode getPolygonModeFront() const;
            void setPolygonModeBack(const PolygonMode pm);
            PolygonMode getPolygonModeBack() const;

            // Polygon Offset
            void setPolygonOffsetPointEnable(const bool b);
            bool isPolygonOffsetPointEnable() const;
            void setPolygonOffsetLineEnable(const bool b);
            bool isPolygonOffsetLineEnable() const;
            void setPolygonOffsetFillEnable(const bool b);
            bool isPolygonOffsetFillEnable() const;
            void setPolygonOffset(const real factor, const real units);
            real getPolygonOffsetFactor() const;
            real getPolygonOffsetUnits() const;

            // Blending
            void setBlendConstantColor(const Color &color);
            Color getBlendConstantColor() const;

            void setBlendEquation(const BlendEquation equ);
            BlendEquation getBlendEquation() const;

            void setBlendEquationSeparate(const BlendEquation colorEqu, const BlendEquation alphaEqu);
            BlendEquation getBlendColorEquation() const;
            BlendEquation getBlendAlphaEquation() const;

            void setBlendFunction(const BlendFunction srcFunc, const BlendFunction dstFunc);
            BlendFunction getBlendSrcFunction() const;
            BlendFunction getBlendDstFunction() const;

            void setBlendFunctionSeparate(const BlendFunction srcColorFunc, const BlendFunction dstColorFunc, const BlendFunction srcAlphaFunc, const BlendFunction dstAlphaFunc);
            BlendFunction getBlendSrcColorFunction() const;
            BlendFunction getBlendDstColorFunction() const;
            BlendFunction getBlendSrcAlphaFunction() const;
            BlendFunction getBlendDstAlphaFunction() const;

            void setBlendEnable(const bool b);
            bool isBlendEnable() const;

            // Lighting
            void setLightEnable(const bool b);
            bool isLightEnable() const;

            // Fog
            void setFog(Fog *pFog);
            Fog* getFog() const;
            void setFogEnable(const bool b);
            bool isFogEnable() const;

            // Color Dithering
            void setDitherEnable(const bool b);
            bool isDitherEnable() const;

            // Multisample
            void setMultisampleEnable(const bool b);
            bool isMultisampleEnable() const;

            // Viewport
            bool setViewport(Viewport *pViewport);
            Viewport* getViewport() const;

            // Material
            void setMaterial(const MaterialPtr &pMaterial);
            MaterialPtr getMaterial() const;
            void setMaterialFront(const MaterialPtr &pMaterial);
            MaterialPtr getMaterialFront() const;
            void setMaterialBack(const MaterialPtr &pMaterial);
            MaterialPtr getMaterialBack() const;

            /*
            void setClipPlanes();

            void setLight(const Light &light, const uint32_t index);

            void setTexture(const Texture &texture, const uint32_t index);

            void setTextureEnv();

            void setProgram(const GLSLProgram &program);

            void setPointParameters();
            */

            virtual ~RenderSystem();

        public:
            static RenderSystem& GetSingleton();

            static RenderSystem* GetSingletonPtr();

        private:
            RenderSystem(const RenderSystem &);

            RenderSystem& operator = (const RenderSystem &);

        private:
            // Matrix
            Matrix4 mProjectionMatrix;
            Matrix4 mViewMatrix;
            Matrix4 mTextureMatrix;
            Matrix4 mColorMatrix;

            // Color Buffer
            Color mClearColor;
            byte mColorWriteMask;

            // Alpha Test
            real mAlphaTestValue;
            CompareFunction mAlphaTestFunc;
            bool mAlphaTestEnable;

            // Depth Buffer Test
            real mClearDepth;
            CompareFunction mDepthTestFunc;
            bool mDepthTestEnable;
            bool mDepthWriteEnable;
            real mDepthNearRange;
            real mDepthFarRange;

            // Stencil Test
            int mClearStencil;
            int mStencilFrontTestValue;
            int mStencilBackTestValue;
            uint32_t mStencilFrontTestMask;
            uint32_t mStencilBackTestMask;
            CompareFunction mStencilFrontTestFunc;
            CompareFunction mStencilBackTestFunc;
            StencilOperation mStencilFrontSrcFailOpt;
            StencilOperation mStencilFrontDstFailOpt;
            StencilOperation mStencilFrontDstPassOpt;
            StencilOperation mStencilBackSrcFailOpt;
            StencilOperation mStencilBackDstFailOpt;
            StencilOperation mStencilBackDstPassOpt;
            uint32_t mStencilFrontWriteEnableMask;
            uint32_t mStencilBackWriteEnableMask;
            bool mStencilTestEnable;

            // Scissor Test
            int mScissorLeft;
            int mScissorBottom;
            uint32_t mScissorWidth;
            uint32_t mScissorHeight;
            bool mScissorTestEnable;

            /*
            // Accumulation Buffer
            Color mClearAccum;
            AccumOperation mAccumOperation;
            */

            // Cull Face
            FrontFaceType mFrontFaceType;
            FaceType mCullFace;
            bool mCullFaceEnable;

            // Polygon Mode
            PolygonMode mPolygonModeFront;
            PolygonMode mPolygonModeBack;

            // Polygon Offset
            bool mPolygonOffsetPointEnable;
            bool mPolygonOffsetLineEnable;
            bool mPolygonOffsetFillEnable;
            real mPolygonOffsetFactor;
            real mPolygonOffsetUnits;

            /*
            // Texturing
            bool mTexture1DEnable;
            bool mTexture2DEnable;
            bool mTexture3DEnable;
            bool mTextureCubeMapEnable;
            bool mTextureGenQEnable;
            bool mTextureGenREnable;
            bool mTextureGenSEnable;
            bool mTextureGenTEnable;
            bool mTextureCubeMapSeamLessEnable;
            */

            // Blending
            Color mBlendConstantColor;
            BlendEquation mBlendColorEquation;
            BlendEquation mBlendAlphaEquation;
            BlendFunction mBlendSrcColorFunc;
            BlendFunction mBlendDstColorFunc;
            BlendFunction mBlendSrcAlphaFunc;
            BlendFunction mBlendDstAlphaFunc;
            bool mBlendEnable;

            // Lighting
            bool mLightEnable;

            // Fog
            Fog *mpFog;
            bool mFogEnable;

            // Dithering
            bool mDitherEnable;
            // Multisample
            bool mMultisampleEnable;
            // Rasterizer Discard
            //bool mRasterizerDiscardEnable;

            /*
            // Multisample Fragment Operations
            bool mSampleAlphaToCoverageEnable;
            bool mSampleAlphaToOneEnable;
            bool mSampleCoverageEnable;
            // SampleCoverage();
            // SampleMaski();
            */

            // Histogram
            //bool mHistogramEnable;

            // Min Max
            //bool mMinMaxEnable;

            // Clipping

            // Normalize
            //bool mAutoNormalEnable;
            //bool mNormalizeEnable;
            //bool mRescaleNormalEnable;

            /*
            // Vertex Program Point Size
            bool mVertexProgramPointSizeEnable;
            bool mVertexProgramTwoSideEnable;

            // Point
            bool mPointSmoothEnable;
            bool mPointSpriteEnable;

            // Line
            bool mLineSmoothEnable;
            bool mLineStippleEnable;

            // Polygon
            bool mPolygonSmoothEnable;
            bool mPolygonStippleEnable;
            */

            // Color Table
            //bool mColorTableEnable;
            //bool mConvolution1DEnable;
            //bool mConvolution2DEnable;
            //bool mSepatable2DEnable;
            //bool mPostColorMatrixColorTableEnable;
            //bool mPostConvolutionColorTableEnable;

            // Primitive Restart
            //bool mPrimiteveRestartEnable;
            //glPrimitiveRestartIndex(uint index);

            /*
            // Color Logical Operation
            ColorLogicalOperation mColorLogicalOperation;
            bool mColorLogicalOperationEnable;
            bool mLogicalOperationEnable;
            bool mIndexLogicalOperationEnable;
            */

            /*
            FRAGMENT_SHADER_DERIVATIVE_HINT,
            TEXTURE_COMPRESSION_HINT,
            POLYGON_SMOOTH_HINT,
            PERSPECTIVE_CORRECTION_HINT,
            FOG_HINT,
            GENERATE_MIPMAP_HINT

            real mPointSize;
            real mLineWidth;

            ShadeModel mShadeModel;
            */

            Viewport *mpViewport;

            // Material
            MaterialPtr mpMaterialFront;
            MaterialPtr mpMaterialBack;

            bool mIsReady;
    };
}

#endif
